package DataModel;

import java.util.ArrayList;

import Interfaces.SortableElements;

/**
 * This class represents a genomic feature with its position, strand and other
 * information.<br>
 * A {@link Feature} exists of a different number of exons which have their
 * positions.<br>
 * This position pairs, start and stop position, are stored in {@link Tupel} and
 * added to the position list.
 * 
 * @author Stefan Lorenz <br>
 *         <b>Date:</b> 12.11.2012
 */
public class Feature implements SortableElements {

    /**
     * The type of a feature can be '+' or '-', depends on which DNA strand it
     */
    private String type;

    /**
     * A list of tupel representing the exon positions
     */
    private ArrayList<Tupel> listOfPositions;

    /**
     * All additional information about a {@link Feature} is stored in this list
     */
    private ArrayList<String> additionalInformation;

    /**
     * Indicates if the {@link Feature} is on the plus or minus stand, therefore
     * it can be '+' or '-'
     */
    private String strand;

    /**
     * The absolute positions are the most left and most right positions of the
     * {@link Feature}
     */
    private Tupel absoultePositions;

    /**
     * The name of the {@link Feature}
     */
    private String name;

    /**
     * The locus name of the {@link Feature}
     */
    private String locus;

    /**
     * The score can represent a expression value
     */
    private float score;

    /**
     * Indicates the track index in which the feature is stored
     */
    private int trackIndex;

    /**
     * Constructor of an empty {@link Feature}
     */
    public Feature() {
	this.type = "";
	this.strand = "";
	this.listOfPositions = new ArrayList<Tupel>();
	this.additionalInformation = new ArrayList<String>();
	this.absoultePositions = new Tupel(0, 0);
	this.name = "";
	this.locus = "";
	this.score = 0;
	this.trackIndex = 0;
    }

    /**
     * Sets the type of the feature like 'mRNA','CDS','exon','gene' etc.
     * 
     * @param type
     *            type of the feature
     */
    public void setType(String type) {
	this.type = type;
    }

    /**
     * Returns the type of the feature
     * 
     * @return type of the feature
     */
    public String getType() {
	return type;
    }

    /**
     * Sets the List with all tupel of positions of this feature
     * 
     * @param listOfPositions
     *            list of all position tupels
     */
    public void setListOfPositions(ArrayList<Tupel> listOfPositions) {
	this.listOfPositions = listOfPositions;
    }

    /**
     * Returns the List of all tupel of positions of this feature
     * 
     * @return list of all position tupels
     */
    public ArrayList<Tupel> getListOfPositions() {
	return listOfPositions;
    }

    /**
     * Adds a new feature to the positions list and sets new absolute positions
     * 
     * @param t
     *            Tupel of positions to add
     */
    public void addTupelToListOfPositions(Tupel t) {
	this.listOfPositions.add(t);
	setAbsoultePositions(new Tupel(this.listOfPositions.get(0).getStart(), this.listOfPositions.get(this.listOfPositions.size() - 1).getStop()));
    }

    /**
     * Sets the List with additional Information like locus_tag dbxref etc
     * 
     * @param additionalInformation
     *            list of additional information
     */
    public void setAdditionalInformation(ArrayList<String> additionalInformation) {
	this.additionalInformation = additionalInformation;
    }

    /**
     * Returns the List with additional Information like locus_tag dbxref etc.
     * 
     * @return list of additional information
     */
    public ArrayList<String> getAdditionalInformation() {
	return additionalInformation;
    }

    /**
     * Sets the strand of the feature
     * 
     * @param strand
     *            strand of feature either '+' or '-'
     */
    public void setStrand(String strand) {
	this.strand = strand;
    }

    /**
     * Returns the strand of the feature
     * 
     * @return strand of feature either '+' or '-'
     */
    public String getStrand() {
	return strand;
    }

    /**
     * Sets the absolute positon start of first exons and end of last exons
     * 
     * @param absoultePositions
     *            absolute positions of feature as tupel
     */
    public void setAbsoultePositions(Tupel absoultePositions) {
	this.absoultePositions = absoultePositions;
    }

    /**
     * Returns the absolute positon start of first exons and end of last exons
     * 
     * @return absolute positions of feature as tupel
     */
    public Tupel getAbsoultePositions() {
	return absoultePositions;
    }

    /**
     * Sets the name of the feature
     * 
     * @param name
     *            the name of the feature
     */
    public void setName(String name) {
	this.name = name;
    }

    /**
     * Returns the name of the feature
     * 
     * @return name of the feature
     */
    public String getName() {
	return name;
    }

    /**
     * Searches for name tags '/gene=' or '/locus_tag=' and sets the name of the
     * feature
     */
    public void getNameOfAdditionalInfo() {
	for (int i = 0; i < additionalInformation.size(); i++) {
	    String temp = additionalInformation.get(i);
	    if (temp.contains("/gene=")) {
		this.name = additionalInformation.get(i).substring(7, temp.lastIndexOf("\""));
	    } else if (temp.contains("/locus_tag=")) {
		this.name = additionalInformation.get(i).substring(12, temp.lastIndexOf("\""));
	    }
	}
    }

    /**
     * Sets the reference locus of the feature. Chromsome or contig name
     * 
     * @param locus
     *            reference of the feature
     */
    public void setLocus(String locus) {
	this.locus = locus;
    }

    /**
     * Returns the reference locus of the feature
     * 
     * @return reference of the feature
     */
    public String getLocus() {
	return locus;
    }

    /*
     * (non-Javadoc)
     * 
     * @see Interfaces.SortableElements#getStart()
     */
    public int getStart() {
	return this.getAbsoultePositions().getStart();
    }

    /*
     * (non-Javadoc)
     * 
     * @see Interfaces.SortableElements#getStop()
     */
    public int getStop() {
	return this.getAbsoultePositions().getStop();
    }

    /**
     * Sets the score of the feature
     * 
     * @param score
     *            score of the feature
     */
    public void setScore(float score) {
	this.score = score;
    }

    /**
     * Returns the score of the feature
     * 
     * @return score of the feature
     */
    public float getScore() {
	return score;
    }

    /**
     * Sets the index of the track of the feature
     * 
     * @param trackIndex
     *            index of the track of the feature
     */
    public void setTrackIndex(int trackIndex) {
	this.trackIndex = trackIndex;
    }

    /**
     * Returns the index of the track of the feature
     * 
     * @return index of the track of the feature
     */
    public int getTrackIndex() {
	return trackIndex;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
	return "Features [type=" + type + ", listOfPositions=" + listOfPositions + ", additionalInformation=" + additionalInformation + ", strand=" + strand + ", absoultePositions=" + absoultePositions + ", name=" + name + ", locus=" + locus + ", score=" + score + ", trackIndex=" + trackIndex + "]";
    }
}
